#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "kernel.h"
// oslib
#include "os.h"
//
#include "proto.h"
#include "instrument.h"
#include "midi.h"
#include "midiport.h"
#include "scheduler.h"
#include "midisupp.h"
#include "100Hz.h"
#include "midi500.h"
#include "externsnd.h"
#include "mcode.h"
#include "linearhndl.h"
#include "loadpatchs.h"
#include "events.h"

// this source file is the main module interface, providing SWIs, commands and more


const char *copyright = " Henrik Bjerregaard Pedersen, 2000-2001";

static void playback_stop(void);
static void playback_start(void);
static void remove_realtime_driver(void);
static void to_uppercase(char *in, char *out, int maxlen);
static void install_realtime_driver(int dt);


#define DRIVER_NONE           0
#define DRIVER_MIDISUPPORT    1
#define DRIVER_100HZ          2
#define DRIVER_MIDI500        3

static int drivertype = DRIVER_NONE;
static void *private;

static char temp[256];


static _kernel_oserror err_bad_args = { 1, "Bad arguments" };
static _kernel_oserror err_reserved_bits_set = { 1, "Reserved bits set" };
static _kernel_oserror err_unknown_reason = { 1, "Unknown reason code" };
static _kernel_oserror err_failed_to_map = { 1, "Failed to map" };
static _kernel_oserror err_failed_to_unmap = { 1, "Failed to unmap patch/sample" };
static _kernel_oserror err_failed_to_create_sample = { 1, "Failed to create sample" };
static _kernel_oserror err_failed_to_remove_sample = { 1, "Failed to remove sample" };
static _kernel_oserror err_failed_to_rename_sample = { 1, "Failed to rename sample" };
static _kernel_oserror err_no_such_sample = { 1, "No such sample" };
static _kernel_oserror err_failed_to_get_sample_info = { 1, "Failed to get sample info" };
static _kernel_oserror err;


int main() {

  return 0;
}


_kernel_oserror *HBP10GM_initialise(char *tail, int base, void *pw) {

  private = pw;
  events_initialise();
  instruments_initialise();
  midi_initialise();
  midiport_initialise();
  externalsnd_initialise();

  return NULL;
}


_kernel_oserror *HBP10GM_finalise(int fatal, int base, void *pw) {

  private = pw;
  generate_event(HBP10GM_EVENT_DYING, 0, 0, 0);
  remove_realtime_driver();
  playback_stop();
  instruments_kill();
  externalsnd_kill();
  midiport_kill();
  midi_kill();

  return NULL;
}


int HBP10GM_service(int serv, _kernel_swi_regs *r, void *pw) {

  private = pw;

  if (serv == 0x58) {                   // service_MIDI
    if (r->r[0] == 0) {                 // alive
      if ((drivertype>>16) == DRIVER_MIDI500)
        install_realtime_driver(DRIVER_MIDI500);
      else if ((drivertype>>16) == DRIVER_MIDISUPPORT)
        install_realtime_driver(DRIVER_MIDISUPPORT);

    } else if (r->r[0] == 1) {          // dying
      if (drivertype == DRIVER_MIDI500) {
        remove_realtime_driver();
        drivertype = DRIVER_MIDI500<<16;
      } else if (drivertype == DRIVER_MIDISUPPORT) {
        remove_realtime_driver();
        drivertype = DRIVER_MIDISUPPORT<<16;
      }
    }
  }

  return 1;
}


_kernel_oserror *HBP10GM_commands(char *tail, int argc, int cmdno, void *pw) {

  private = pw;

  if (cmdno == 0) {           // *HBP10GM_Config <name> <value>
    if (argc == 0) {
      int val;

      midi_control(MIDICTRL_FREQ | MIDICTRL_READONLY, 0, 0, &val);
      printf("  FREQ        %d Hz\n", val);
      midi_control(MIDICTRL_POLYPHONY | MIDICTRL_READONLY, 0, 0, &val);
      printf("  POLY        %d notes\n", val);
      midi_control(MIDICTRL_TUNING | MIDICTRL_READONLY, 0, 0, &val);
      printf("  TUNING      %d semitones\n", val);
      midi_control(MIDICTRL_VOLUME | MIDICTRL_READONLY, 0, 0, &val);
      printf("  VOLUME      %d (4096=0dB)\n", val);
      midi_control(MIDICTRL_INTERPOLATE | MIDICTRL_READONLY, 0, 0, &val);
      if (val)
        printf("  INTERPOLATE 1 (enabled)\n");
      else
        printf("  INTERPOLATE 0 (disabled)\n");
      midi_control(MIDICTRL_BASECHANNEL | MIDICTRL_READONLY, 0, 0, &val);
      printf("  BASECHANNEL %d \n", val);
      generate_event(HBP10GM_EVENT_CONFIG_REQUEST, 0, 0, 0);

    } else if (argc == 2) {
      int val;

      if (sscanf(tail, "%s %d", temp, &val) == 2) {
        to_uppercase(temp, temp, 256);

        if (strcmp(temp, "FREQ") == 0)
          midi_control(MIDICTRL_FREQ, val, 0, NULL);
        else if (strcmp(temp, "POLY") == 0)
          midi_control(MIDICTRL_POLYPHONY, val, 0, NULL);
        else if (strcmp(temp, "VOLUME") == 0)
          midi_control(MIDICTRL_VOLUME, val, 0, NULL);
        else if (strcmp(temp, "TUNING") == 0)
          midi_control(MIDICTRL_TUNING, val, 0, NULL);
        else if (strcmp(temp, "INTERPOLATE") == 0)
          midi_control(MIDICTRL_INTERPOLATE, val, 0, NULL);
        else if (strcmp(temp, "BASECHANNEL") == 0)
          midi_control(MIDICTRL_BASECHANNEL, val, 0, NULL);
        else if (strcmp(temp, "DRUM") == 0) {
          int chn;
          for (chn = 0; chn < 16; chn++)
            if (chn == val-1)
              midi_control_channel(MIDICTRL_CHN_IS_DRUM, 1 | (chn<<8), 0, NULL);
            else
              midi_control_channel(MIDICTRL_CHN_IS_DRUM, 0 | chn<<8, 0, NULL);
        } else {
          generate_event(HBP10GM_EVENT_UNKNOWN_CONFIG, (int)temp, val, 0);
        }
      }
    }

  } else if (cmdno == 1) {    // *HBP10GM_RealTime <drivertype>

    while (*tail == ' ')  tail++;
    to_uppercase(tail, temp, 256);

    if (argc == 1) {
      if (strncmp(temp, "MIDISUPPORT", 11) == 0) {
        remove_realtime_driver();
        install_realtime_driver(DRIVER_MIDISUPPORT);

      } else if (strncmp(temp, "100HZ", 5) == 0) {
        remove_realtime_driver();
        install_realtime_driver(DRIVER_100HZ);

      } else if (strncmp(temp, "MIDI500", 7) == 0) {
        remove_realtime_driver();
        install_realtime_driver(DRIVER_MIDI500);

      } else if (strncmp(temp, "?", 1) == 0) {
        char *stat;
        int dt;

        stat = "";
        dt = drivertype;
        if (dt & 0xffff0000) {
          dt = drivertype>>16;
          stat = "(dormant)";
        }

        switch (dt) {
        case DRIVER_MIDISUPPORT:
          printf("  MIDISupport %s\n", stat);
          break;
        case DRIVER_100HZ:
          printf("  100Hz %s\n", stat);
          break;
        case DRIVER_MIDI500:
          printf("  MIDI500 %s\n", stat);
          break;
        default:
          printf("  no driver installed\n");
          break;
        }
      }

    } else if (argc == 0)
      remove_realtime_driver();

  } else if (cmdno == 2) {    // *HBP10GM_Playback [0 | 1]
    switch (atoi(tail)) {
    case 0:
      playback_stop();
      break;
    case 1:
      playback_start();
      break;
    }

  } else if (cmdno == 3) {    // *HBP10GM_LoadPatch <filename>
    char *errmess;

    errmess = load_patches(tail);
    if (errmess) {
      err.errnum = 1;
      strcpy(err.errmess, errmess);
      return &err;
    }

  } else if (cmdno == 4) {    // *HBP10GM_Patches [<bank>]
    unsigned int banki0, banki1, banki;
    if (argc == 0) {
      banki0 = 0;
      banki1 = 15;
    } else {
      banki0 = banki1 = atoi(tail)-1;
      if (banki0 >= 16)  return &err_bad_args;
    }
    for (banki = banki0; banki <= banki1; banki++) {
      unsigned int patchi, first;
      first = 1;
      for (patchi = 0; patchi < 128; patchi++) {
        PATCH *patch;
        patch = instruments_get_patch(banki, patchi);
        if (patch) {
          if (first)  printf("# BANK %02d\n", banki+1);
          first = 0;
          if (patch->name[0])
            printf("%03d %s\n", patchi+1, patch->name);
        }
      }
      first = 1;
      for (patchi = 0; patchi < 128; patchi++) {
        DRUM *drum;
        drum = instruments_get_drum(banki, patchi);
        if (drum) {
          if (first)  printf("# BANK %02d - DRUMS\n", banki+1);
          first = 0;
          if (drum->name[0])
            printf("%03d %s\n", patchi+1, drum->name);
        }
      }
    }
  }

  return NULL;
}


_kernel_oserror *HBP10GM_swi_handler(int swi, _kernel_swi_regs *r, void *pw) {

  int rval;

  rval = 0;
  private = pw;

  switch (swi) {
  case 0:           // HBP10GM_TxBytes
    {
      // on entry
      // r0 -> buffer
      // r1 =  bytes to send
      // on exit
      // r0 =  bytes free in buffer
      int available;

      midi_rx_bytes(NULL, (unsigned char *)r->r[0], r->r[1], &available);
      rval = available;
    }
    break;

  case 1:           // HBP10GM_ReadSamples
    // on entry
    // r0 -> buffer
    // r1 =  samples
    // r2 =  flags
    //       bit 0 set     update ticker as specified by bit 1
    //       bit 1 clear   increment ticker by (ticks/second)*(samples/frequency)
    //       bit 1 set     increment ticker by value in r3
    //       bit 2 set     stereo
    //       bit 3 set     clear buffer first
    //       bit 3 clear   buffer already contains 0
    //       bit 4 set     reduce to 16 bits (instead of 32 bits)
    //       bit 5 set     interpolate samples
    // r3 =  ticker-increment (is bit 0 set and bit 1 set)
    {
      unsigned int flags;

      flags = r->r[2];
      if (flags & 0xffffffc0)   return &err_reserved_bits_set;
      if (flags & MIDI_UPDATE_TICKER) {
        if (flags & MIDI_INCR_TICKER_TYPE)
          scheduler_increment_ticker(r->r[3], 0);
        else
          scheduler_increment_ticker(r->r[1], midi_read_frequency());
        flags &= ~(MIDI_UPDATE_TICKER | MIDI_INCR_TICKER_TYPE);  // clear bits
      }
      midi_read_samples((signed short *)r->r[0], r->r[1], flags, NULL);
    }
    break;

  case 2:           // HBP10GM_TxCommand
    {
      // on entry
      // r0 =  d2d1d0nn       nn      = no. of data bytes
      // r1 =  d6d5d4d3       d0..d6  = up to 7 data bytes
      int available;
      unsigned char buffer[8];

      ((int *)buffer)[0] = r->r[0];
      ((int *)buffer)[1] = r->r[1];
      midi_rx_bytes(NULL, buffer+1, (*buffer)&7, &available);
    }
    break;

  case 3:           // HBP10GM_Ticker
    { // manages the internal ticker
      // on entry
      // r0 =  reason code in bits 0..7
      //       0    reset ticker to 0
      //       1    read ticker
      //       2    set ticker to value in r1
      //       3    increment ticker by value in r1
      //       4    set ticks/seconds
      //       5    read ticks/seconds
      //       6    increment by r1/r2 seconds
      //       7    flush eventbuffer
      if (r->r[0] & 0xffffff00)   return &err_reserved_bits_set;
      switch (r->r[0] & 255) {
      case 0:
        scheduler_set_ticker(0);
        break;
      case 1:
        rval = scheduler_read_ticker();
        break;
      case 2:
        scheduler_set_ticker(r->r[1]);
        break;
      case 3:
        scheduler_increment_ticker(r->r[1], 0);
        break;
      case 4:
        scheduler_set_tickspersecond(r->r[1]);
        break;
      case 5:
        rval = scheduler_read_tickspersecond();
        break;
      case 6:
        scheduler_increment_ticker(r->r[1], r->r[2]);
        break;
      case 7:
        scheduler_flush_buffer();
        break;
      default:
        return &err_unknown_reason;
        break;
      }
    }
    break;

  case 4:           // HBP10GM_Schedule
    {
      // on entry
      // r0 =  d2d1d0nn       nn      = no. of data bytes
      // r1 =  d6d5d4d3       d0..d6  = up to 7 data bytes
      // r2 =  ticker value to schedule for
      // on exit
      // r0 =  -1 (failed) or amount of free space in the command buffer
      if (r->r[0] == -1)
        scheduler_info(&rval, &r->r[1], &r->r[2], &r->r[3], &r->r[4], &r->r[5]);
      else
        rval = schedule_event(r->r[0], r->r[1], r->r[2]);
    }
    break;

  case 5:           // HBP10GM_Playback
    // on entry
    // r0 =  0      stop playback
    //       1      play using 16 bit Acorn interface
    //       2      read address of sample-generating routine
    if (r->r[0] & 0xffffff00)   return &err_reserved_bits_set;
    switch (r->r[0] & 255) {
    case 0:
      playback_stop();
      break;
    case 1:
      playback_start();
      break;
    case 2:
      rval = (int)midi_generate_samples;
      break;
    default:
      return &err_unknown_reason;
      break;
    }
    break;

  case 6:         // HBP10GM_ControlSamples
    switch (r->r[0] &255) {
    case 0:
      { // get samplehandle
        unsigned int banki, notei;

        if (r->r[0] & 0xf8000000)  return &err_reserved_bits_set;
        banki    = (r->r[0]>>8)  &15;
        notei    = (r->r[0]>>20) &127;
        if (r->r[0] & (1<<12)) {
          DRUM *d;

          d = instruments_get_drum(banki, notei);
          if (d)
            rval = d->sample;
          else
            rval = -1;

        } else {
          PATCH *p;
          unsigned int patchi;

          patchi = (r->r[0]>>13) &127;
          p = instruments_get_patch(banki, patchi);
          if (p)
            rval = p->samples[notei/12];
          else
            rval = -1;
        }
      }
      break;
    case 1: // create sample
      {
        unsigned int format, ext;
        SAMPLEINDEX si;

        if (r->r[0] & 0xfffe0000)  return &err_reserved_bits_set;
        format = (r->r[0]>>8) &15;
        ext = 0;
        if (r->r[0] & (1<<16))   ext = 1;
        si = instruments_new_sample((char *)r->r[2], r->r[1], ext, r->r[4], format);
        if (si == ILLEGAL_SAMPLE)  return &err_failed_to_create_sample;
        rval = si;
      }
      break;
    case 2: // remove sample
      if (r->r[0] & 0xffffff00)                return &err_reserved_bits_set;
      if (instruments_remove_sample(r->r[1]))  return &err_failed_to_remove_sample;
      break;
    case 3: // map sample to patch
      {
        unsigned int banki, notei, patchi;
        SAMPLEINDEX si;

        if (r->r[0] & 0xe0000000)              return &err_reserved_bits_set;
        if (r->r[0] & (1<<28)) {
          char name[16];

          strncpy(name, (char *)r->r[1], 15);
          name[15] = '\0';
          si = instruments_find_named_sample(name);
          if (si == ILLEGAL_SAMPLE)            return &err_no_such_sample;
        } else
          si = r->r[1];
        banki = (r->r[0]>>8) &15;
        notei = (r->r[0]>>20) &127;
        patchi = (r->r[0]>>13) &127;
        if (si == -1) {
          // remove mapping
          if (r->r[0] & (1<<12)) {
            unsigned int oct;

            if (r->r[0] &(1<<27))
              oct = ALL_OCTAVES;
            else
              oct = notei/12;

            if (instruments_unmap(banki, patchi, oct))   return &err_failed_to_unmap;
          } else {
            if (instruments_unmap_drum(banki, notei))    return &err_failed_to_unmap;
          }
        } else {
          if (r->r[0] & (1<<12)) {
            unsigned int oct;

            if (r->r[0] &(1<<27))
              oct = ALL_OCTAVES;
            else
              oct = notei/12;
            if (instruments_map(si, banki, patchi, oct, r->r[2]))
              return &err_failed_to_map;
          } else {
            if (instruments_map_drum(si, banki, notei, r->r[2]))
              return &err_failed_to_map;
          }
        }
      }
      break;
    case 4: // get sample info
      {
        unsigned int *info;

        if (r->r[0] & 0xffffff00)                return &err_reserved_bits_set;
        info = (unsigned int *)r->r[2];
        if (instruments_get_sample_info2(r->r[1], (char *)(info)+8, NULL))
          return &err_failed_to_get_sample_info;
        if (instruments_get_sample_info(r->r[1], NULL, info+0, info+1, NULL))
          return &err_failed_to_get_sample_info;
      }
      break;
    case 5: // set samplename
      if (r->r[0] & 0xffffff00)                return &err_reserved_bits_set;
      if (instruments_set_sample_name(r->r[1], (char *)r->r[2]))
                                               return &err_failed_to_rename_sample;
      break;
    case 6: // enumerate samples
      if (r->r[0] & 0xffffff00)                return &err_reserved_bits_set;
      rval = instruments_enumerate_samples(r->r[1], NULL, NULL);
      if (rval == ILLEGAL_SAMPLE)  rval = -1;
      break;
    case 7: // set default sample
      if (r->r[0] & 0xffffff00)                return &err_reserved_bits_set;
      if (r->r[1] == -1)
        instruments_set_default_sample(ILLEGAL_SAMPLE);
      else
        instruments_set_default_sample(r->r[1]);
      break;
    case 8: // get patch info
      {
        unsigned int banki, notei, patchi;

        if (r->r[0] & 0xf0000000)              return &err_reserved_bits_set;

        banki = (r->r[0]>>8) &15;
        notei = (r->r[0]>>20) &127;
        patchi = (r->r[0]>>13) &127;

        rval = -1;
        if (r->r[0] & (1<<12)) {
          PATCH *patch;
          unsigned int oct;

          oct = notei/12;
          patch = instruments_get_patch(banki, patchi);
          if (patch)
            if (patch->name[0]) {
              if (r->r[1])  strcpy((char *)r->r[1], patch->name);
              rval = patch->samples[oct];
              if (rval == ILLEGAL_SAMPLE)
                rval = -1;
              else
                r->r[2] = patch->frequency[oct];
            }
        } else {
          DRUM *drum;

          drum = instruments_get_drum(banki, patchi);
          if (drum)
            if (drum->name[0]) {
              if (r->r[1])  strcpy((char *)r->r[1], drum->name);
              rval = drum->sample;
              if (rval == ILLEGAL_SAMPLE)
                rval = -1;
              else
                r->r[2] = drum->frequency;
            }
        }
      }
      break;
    case 9: // find sample
      {
        SAMPLEINDEX si;
        char name[16];
        strncpy(name, (char *)r->r[1], 15);
        name[15] = '\0';
        si = instruments_find_named_sample(name);
        if (si == ILLEGAL_SAMPLE)
          return &err_no_such_sample;
        else
          rval = si;
      }
      break;
    case 10: // read sample address
      {
        signed short *data;

        if (instruments_get_sample_info(r->r[1], &data, NULL, NULL, NULL))
          return &err_failed_to_get_sample_info;
        r->r[0] = (int)data;
        return NULL;
      }
      break;
    case 11: // generate FM waveform
      build_from_harmonics((signed short *)r->r[1], r->r[2], r->r[3],
                           (int *)r->r[4], SAMPLE_SINE);
      rval = 0;
      break;
    default:
      return &err_unknown_reason;
      break;
    }
    break;

  case 7:         // HBP10GM_Control
    return midi_control(r->r[0], r->r[1], r->r[2], &r->r[0]);
    break;

  case 8:        // HBP10GM_Monitor
    return midi_monitor(r->r[0], r->r[1], r->r[2], &r->r[0]);
    break;

  case 9:         // HBP10GM_ControlChannel
    return midi_control_channel(r->r[0], r->r[1], r->r[2], &r->r[0]);
    break;

  case 10:        // HBP10GM_ControlPatches
    return midi_control_patches(r->r[0], r->r[1], r->r[2], &r->r[0]);
    break;

  case 11:        // HBP10GM_ExternalVoice
    // on entry
    // r0 =  reason code in bits 0..7
    //       0  install voice generator
    //            bank no. in bits 8..11
    //            program no. in bits 13..19
    //          r1 -> control block
    //          r2 -> sample/patch name
    //       1  remove voice generator
    //          r1 -> control block
    switch (r->r[0] & 255) {
    case 0:
      {
        unsigned int banki, programi;

        if (r->r[0] & 0xfff01000)   return &err_reserved_bits_set;
        banki = (r->r[0]>>8) &15;
        programi = (r->r[0]>>13) &127;
        return externalsnd_install(banki, programi, (VOICEGENERATOR *)r->r[1], (char *)r->r[2]);
      }
      break;
    case 1:
      if (r->r[0] & 0xfffff00)   return &err_reserved_bits_set;
      return externalsnd_remove((VOICEGENERATOR *)r->r[1]);
      break;
    default:
      return &err_unknown_reason;
      break;
    }
    break;

  case 12:          // HBP10GM_Info
    return midi_info(r->r[0], r->r[1], &r->r[0]);
    break;

  case 13:          // HBP10GM_Ports
    // on entry
    // r0 =  reason code in bits 0..7
    //       port no. in bits 8..15 (if reason code <> 0)
    //       0  create new port
    //          r1 =  frequency
    //          r2 =  features word or 0 for default
    //                bits  0..3   basechannel
    //                bits  4..8   tuning (signed 4 bit value)
    //                bits  9..14  maximum polyphony - 1
    //          on exit
    //          r0 =  port number (1..255)
    //       1  delete port
    //       2  tx bytes
    //          r1 -> buffer
    //          r2 =  no. of bytes
    //          on exit
    //          r0 =  no. of free bytes left in buffer
    //       3  tx command
    //          r1 =  d2d1d0nn       nn      = no. of data bytes
    //          r2 =  d6d5d4d3       d0..d6  = up to 7 data bytes
    //          on exit
    //          r0 =  no. of free bytes left in buffer
    //       4  tx small command
    //          r1 =  d2d1d0nn       nn      = no. of data bytes
    //          on exit
    //          r0 =  no. of free bytes left in buffer
    //       5  read samples
    //          r1 -> buffer
    //          r2 =  samples
    //          r3 =  flags
    //                bit 2 set     stereo
    //                bit 3 set     clear buffer
    //                bit 4 set     reduce to 16 bits (instead of 32 bits)
    //                bit 5 set     interpolate samples
    //       6  read info
    //          r1 =  subreason code
    //          on exit
    //          r0 =  return value
    return midiport(r->r[0], r->r[1], r->r[2], r->r[3], &r->r[0], &r->r[1]);
    break;

  case 14:          // HBP10GM_Events
    switch (r->r[0]) {
    case 0:         // claim
      return events_install(r->r[1], (void *)r->r[2], r->r[3]);
      break;
    case 1:         // release
      return events_remove(r->r[1], (void *)r->r[2], r->r[3]);
      break;
    default:
      return &err_unknown_reason;
      break;
    }
    break;
  }

  r->r[0] = rval;

  return NULL;
}


// --------------------------------------------------------------------------

void remove_realtime_driver() {

  switch (drivertype) {
  case DRIVER_MIDISUPPORT:
    midisupport_kill(private);
    break;
  case DRIVER_100HZ:
    _100Hz_remove();
    break;
  case DRIVER_MIDI500:
    midi500_kill(private);
    break;
  case DRIVER_NONE:
    return;
    break;
  }
  drivertype = DRIVER_NONE;
  generate_event(HBP10GM_EVENT_REALTIME_INPUT_DISABLED, 0, 0, 0);
}


void install_realtime_driver(int dt) {

  switch (dt) {
  case DRIVER_MIDISUPPORT:
    if (!midisupport_init(private)) {
      drivertype = DRIVER_MIDISUPPORT;
      generate_event(HBP10GM_EVENT_REALTIME_INPUT_ENABLED, drivertype, 0, 0);
    } else
      drivertype = DRIVER_MIDISUPPORT<<16;
    break;

  case DRIVER_100HZ:
    if (!_100Hz_install()) {
      drivertype = DRIVER_100HZ;
      generate_event(HBP10GM_EVENT_REALTIME_INPUT_ENABLED, drivertype, 0, 0);
    } else
      drivertype = DRIVER_NONE;
    break;

  case DRIVER_MIDI500:
    if (!midi500_init(private)) {
      drivertype = DRIVER_MIDI500;
      generate_event(HBP10GM_EVENT_REALTIME_INPUT_ENABLED, drivertype, 0, 0);
    } else
      drivertype = DRIVER_MIDI500<<16;
    break;
  }
}


void to_uppercase(char *in, char *out, int maxlen) {

  int i;

  i = 0;
  while ((in[i]) && (i < maxlen)) {
    out[i] = toupper(in[i]);
    i++;
  }
  out[i] = '\0';
}

// --------------------------------------------------------------------------

static int playing = 0;


void playback_stop() {

  if (!playing)  return;

  linearhandler_stop();
  playing = 0;
  generate_event(HBP10GM_EVENT_REALTIME_OUTPUT_DISABLED, 0, 0, 0);
}


void playback_start() {

  if (playing)   playback_stop();

  if (linearhandler_start(midi_read_frequency(),
                          (void *)linear_handler,
                          (void *)midi_get_default_port()) == 0) {
    playing = 1;
    generate_event(HBP10GM_EVENT_REALTIME_OUTPUT_ENABLED, 0, 0, 0);
  }
}

